package org.zlb.algorithm.distance;

/**
 * 余弦相似度
 * @author zhoulingbo
 * @date 2021/09/10
 */
public class Cosine {

    /**
     * 向量v1、v2的余弦相似度
     * @param v1
     * @param v2
     * @return
     */
    public static double r(double[] v1, double[] v2) {
        if (v1.length != v2.length)
            return -1;
        
        double sum = 0;
        double x = 0;
        double y = 0;
        
        for (int i=0; i<v1.length; i++) {
            sum += v1[i] * v2[i];
            x += Math.pow(v1[i], 2);
            y += Math.pow(v2[i], 2);
        }
        
        if (x == 0 && y == 0)
            return 1;
        
        if (x == 0 || y == 0)
            return 0;
        
        return sum / (x * y);
    }
    
    /**
     * 修正余弦相似度
     * @param v1
     * @param v2
     * @return
     */
    public static double rAdjusted(double[] v1, double[] v2) {
        if (v1.length != v2.length)
            return -1;
        
        int n = v1.length;
        double sumx = 0.0;
        double sumy = 0.0;
        for (int i=0; i<v1.length; i++) {
            sumx += v1[i];
            sumy += v2[i];
        }
        
        double avgx = sumx/n;
        double avgy = sumy/n;
        
        double sumxy = 0.0;
        double sumxx = 0.0;
        double sumyy = 0.0;
        for (int i=0; i<v1.length; i++) {
            sumxy += (v1[i] - avgx) * (v2[i] - avgy);
            sumxx += Math.pow(v1[i]-avgx, 2);
            sumyy += Math.pow(v2[i]-avgy, 2);
        }
        
        return sumxy / (Math.sqrt(sumxx) * Math.sqrt(sumyy));
    }
    
}
